import os
import time
import random
import threading
import subprocess
import socket
import requests
import yaml

from utils.teambition import Doctor, Health, Manage, H, HHealth
from utils.tools import log, tools
from utils.ding_hook import ding_hook
from utils.teambition import share_folder

_dir = os.path.dirname(__file__)
_cookie_useful_file = os.sep.join([_dir, 'conf', 'cookie_useful.yml'])


# 执业版的线程 :
# 当前并未实现多线程下载, 多线程下载需要一个单例的东西, 存储正在下载的 apk
def download_doctor():
    doctor = Doctor()
    log.debug(f'查询 __医生端__ 是否有新包')
    doctor.download_all()


# 患者版的线程 :
# 当前并未实现多线程下载, 多线程下载需要一个单例的东西, 存储正在下载的 apk
def download_health():
    health = Health()
    log.debug(f'查询 __患者端__ 是否有新包')
    health.download_all()


# 健管版的线程 :
# 当前并未实现多线程下载, 多线程下载需要一个单例的东西, 存储正在下载的 apk
def download_manage():
    manage = Manage()
    log.debug(f'查询 __健管端__ 是否有新包')
    manage.download_all()


# 全病程的线程 :
# 当前并未实现多线程下载, 多线程下载需要一个单例的东西, 存储正在下载的 apk
def download_h():
    h = H()
    log.debug(f'查询 __全病程__ 是否有新包')
    h.download_all()


# 全病程_患者版_的线程 :
# 当前并未实现多线程下载, 多线程下载需要一个单例的东西, 存储正在下载的 apk
# 全病程下的患者版, 坑死, 前端提测/医链健康-APP, 该目录的更新时间不会随着子目录的更新时间同步更新,,,
def download_h_health():
    h_health = HHealth()
    log.debug(f'查询 __全病程/患者端__ 是否有新包')
    h_health.download_all()


# 局域网 websocket 分享 :
def share(ip='192.168.1.119', port: int = 8000):
    """
    自动获取本机 IP 地址
    如果获取不到, 就使用参数定义的 IP 地址
    """

    def get_local_ip():
        try:
            # 创建一个 socket 对象
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            # 连接远程地址，随便填一个不影响的地址和端口
            s.connect(('8.8.8.8', 80))
            # 获取本地 IP 地址
            _local_ip = s.getsockname()[0]
            print('获取到本地 IP 地址:', _local_ip)
        except Exception as e:
            print('获取本地 IP 地址失败:', e)
            _local_ip = ip
        return _local_ip

    _ip = get_local_ip()

    subprocess.run(["python", "-m", "http.server", str(port), "--bind", _ip, "--directory", share_folder])


# 运行次数 :
def run_times(begin_time):
    current_time = time.time()
    run_time = current_time - begin_time
    if run_time < 60:
        # print(f'已运行: -> {int(run_time // 1)} 秒')
        log.info(f'已运行: -> {int(run_time // 1)} 秒')
    elif 60 ** 2 > run_time >= 60:
        # print(f'已运行: -> {int(run_time // 60)} 分, {int(run_time % 60)} 秒')
        log.info(f'已运行: -> {int(run_time // 60)} 分, {int(run_time % 60)} 秒')
    elif run_time > 60 ** 2:
        # print(f'已运行: -> {int(run_time // 60 // 60)} 时,  {int(run_time // 60 % 60)} 分, {int(run_time % 60)} 秒')
        log.info(f'已运行: -> {int(run_time // 60 // 60)} 时,  {int(run_time // 60 % 60)} 分, {int(run_time % 60)} 秒')


# auto_pause
def auto_pause(_pause: int):
    # auto_teambition 项目总是在 02:59:00 停止运行,
    # 因此每当晚上 02:55:00 之后, 让 auto_teambition 自动暂停一段时间 ( _pause * 60 )
    _time = time.localtime()
    _hour = _time.tm_hour
    if _hour == 2:
        _min = _time.tm_min
        if _min >= 55:
            time.sleep(60 * _pause)


def main():
    i = 0
    exception_time = 0
    _begin_time = time.time()

    # 开放局域网访问:
    # 必须启动新的线程
    # # http://192.168.1.119:8000
    thread_share = threading.Thread(target=share, name=',local_http_server')
    thread_share.start()

    while True:

        # 添加 try:
        try:

            i += 1
            _current_time = tools.time2date(time.time())

            # 02:55:00 之后, 暂停 8 分钟,
            auto_pause(8)

            # 看到这块代码不要笑, run() 其实是单线程的, 但是如果改成 start() 就需要每次下载后, 把下载状态保存起来, 倒是不难, 就是没时间写 ...
            # 原因是, 等待只等 20s 左右, 而下载需要分钟级, 我上一次下载还没完成呢, 也就是文件还没创建出来呢, 下一次下载就又开始执行了, 循环白下

            thread_doctor = threading.Thread(target=download_doctor, name='thread_doctor')
            thread_doctor.run()

            thread_health = threading.Thread(target=download_health, name='thread_health')
            thread_health.run()

            thread_manage = threading.Thread(target=download_manage, name='thread_manage')
            thread_manage.run()

            thread_h = threading.Thread(target=download_h, name='thread_h')
            thread_h.run()

            thread_h_health = threading.Thread(target=download_h_health, name='download_h_health')
            thread_h_health.run()

            # 如果 cookies 过期, 通知钉钉:
            with open(_cookie_useful_file, mode='r', encoding='utf8') as f:
                _data: dict = yaml.safe_load(f)
                log.debug(f'cookie_useful.yml 内容: << {_data} >>')
                _useful = _data.get('useful')
                if not _useful:
                    ding_hook.text()
                else:
                    log.debug('cookie 尚且有效, 不用担心 ~ ~ ~')

            log.info(f'已运行: {i} 次')
            run_times(_begin_time)

            # 每 30 次, 通知一次钉钉, 差不多 20 多分钟通知一次
            ding_hook.running_message(i) if i % 30 == 0 else False

            time.sleep(random.choice([i for i in range(39, 49, 2)]))

        except ConnectionAbortedError as e:
            exception_time += 1
            print('异常:', e)
            time.sleep(3)
            if exception_time > 5:
                log.warning('异常超过 5 次, 已停止查询 ~ ~ ~')
                ding_hook.running_message(i, _exception_times=exception_time, _exception=True, _is_at=True)
                break
            log.exception(f'第 {exception_time} 次异常')
            continue
        except requests.exceptions.ConnectionError as e:
            exception_time += 1
            print('异常:', e)
            time.sleep(3)
            if exception_time > 5:
                log.warning('异常超过 5 次, 已停止查询 ~ ~ ~')
                ding_hook.running_message(i, _exception_times=exception_time, _exception=True, _is_at=True)
                break
            log.exception(f'第 {exception_time} 次异常')
            continue
        except Exception as e:
            exception_time += 1
            print('异常', e)
            time.sleep(3)
            if exception_time > 5:
                log.warning('异常超过 5 次, 已停止查询 ~ ~ ~')
                ding_hook.running_message(i, _exception_times=exception_time, _exception=True, _is_at=True)
                break
            log.exception(f'第 {exception_time} 次异常')
            continue


main()
